
use std::io::{self, BufReader, BufRead};
use crate::IResult;
use encoding_rs::Encoding;

use super::bytes_io::BytesIO;


impl BytesIO {
    fn read_1(&mut self) -> io::Result<u8> {
        let len = super::bytes_io::LEN_1;
        if self.pos + len > self.bytes.len() {
            let msg = format!("BytesIO::read_1, end of memory: {}(pos) + {}(read) = {} > {}(len)",
                self.pos, len, self.pos + len, self.bytes.len());
            return Err(io::Error::new(io::ErrorKind::OutOfMemory, msg));
        }
        let bt = self.bytes[self.pos];
        self.pos += len;

        Ok(bt)
    }
    fn read_2(&mut self) -> io::Result<[u8; super::bytes_io::LEN_2]> {
        let len = super::bytes_io::LEN_2;
        if self.pos + len > self.bytes.len() {
            let msg = format!("BytesIO::read_2, end of memory: {}(pos) + {}(read) = {} > {}(len)",
                self.pos, len, self.pos + len, self.bytes.len());
            return Err(io::Error::new(io::ErrorKind::OutOfMemory, msg));
        }
        let slice_src = &self.bytes[self.pos..(self.pos) + len];
        let mut arr_byte = [0_u8; super::bytes_io::LEN_2];
        for i in 0..len {
            arr_byte[i] = slice_src[i];
        }
        self.pos += len;

        Ok(arr_byte)
    }
    fn read_4(&mut self) -> io::Result<[u8; super::bytes_io::LEN_4]> {
        let len = super::bytes_io::LEN_4;
        if self.pos + len > self.bytes.len() {
            let msg = format!("BytesIO::read_4, end of memory: {}(pos) + {}(read) = {} > {}(len)",
                self.pos, len, self.pos + len, self.bytes.len());
            return Err(io::Error::new(io::ErrorKind::OutOfMemory, msg));
        }
        let slice_src = &self.bytes[self.pos..(self.pos) + len];
        let mut arr_byte = [0_u8; super::bytes_io::LEN_4];
        for i in 0..len {
            arr_byte[i] = slice_src[i];
        }
        self.pos += len;

        Ok(arr_byte)
    }
    fn read_8(&mut self) -> io::Result<[u8; super::bytes_io::LEN_8]> {
        let len = super::bytes_io::LEN_8;
        if self.pos + len > self.bytes.len() {
            let msg = format!("BytesIO::read_8, end of memory: {}(pos) + {}(read) = {} > {}(len)",
                self.pos, len, self.pos + len, self.bytes.len());
            return Err(io::Error::new(io::ErrorKind::OutOfMemory, msg));
        }
        let slice_src = &self.bytes[self.pos..(self.pos) + len];
        let mut arr_byte = [0_u8; super::bytes_io::LEN_8];
        for i in 0..len {
            arr_byte[i] = slice_src[i];
        }
        self.pos += len;

        Ok(arr_byte)
    }
    fn read_16(&mut self) -> io::Result<[u8; super::bytes_io::LEN_16]> {
        let len = super::bytes_io::LEN_16;
        if self.pos + len > self.bytes.len() {
            let msg = format!("BytesIO::read_16, end of memory: {}(pos) + {}(read) = {} > {}(len)",
                self.pos, len, self.pos + len, self.bytes.len());
            return Err(io::Error::new(io::ErrorKind::OutOfMemory, msg));
        }
        let slice_src = &self.bytes[self.pos..(self.pos) + len];
        let mut arr_byte = [0_u8; super::bytes_io::LEN_16];
        for i in 0..len {
            arr_byte[i] = slice_src[i];
        }
        self.pos += len;

        Ok(arr_byte)
    }

    pub fn read_bytes(&mut self, len: usize) -> io::Result<Vec<u8>> {
        if self.pos + len > self.bytes.len() {
            let msg = format!("BytesIO::read, end of memory: {}(pos) + {}(read) = {} > {}(len)",
                self.pos, len, self.pos + len, self.bytes.len());
            return Err(io::Error::new(io::ErrorKind::OutOfMemory, msg));
        }
        let blob = self.bytes[self.pos..(self.pos + len)].to_vec();
        self.pos += len;
        
        Ok(blob)
    }
    pub fn read_blob_with_size(&mut self) -> io::Result<(i32, Vec<u8>)> {
        let len = self.read_i32_le()?;
        if len < 1 {
            return Ok((len, vec![]));
        }
        let blob = self.read_bytes(len as usize)?;

        Ok((len, blob))
    }

    pub fn read_utf8_with_size(&mut self) -> io::Result<(i32, String)> {
        let len = self.read_i32_le()?;
        if len < 1 {
            return Ok((len, "".to_string()));
        }
        let blob = self.read_bytes(len as usize)?;
        
        match String::from_utf8(blob) {
            Ok(content) => Ok((len, content)),
            Err(e) => Err(io::Error::new(io::ErrorKind::InvalidData, e)),
        }
    }
}

impl BytesIO {
    pub fn read_bool(&mut self) -> io::Result<bool> {
        let val = self.read_1()?;
        Ok(val != 0)
    }
    pub fn read_i8(&mut self) -> io::Result<i8> {
        let val = self.read_1()?;
        Ok(val as i8)
    }
    pub fn read_u8(&mut self) -> io::Result<u8> {
        self.read_1()
    }
}


impl BytesIO {
    pub fn read_i16_le(&mut self) -> io::Result<i16> {
        let arr_byte = self.read_2()?;
        Ok(i16::from_le_bytes(arr_byte))
    }
    pub fn read_i16_be(&mut self) -> io::Result<i16> {
        let arr_byte = self.read_2()?;
        Ok(i16::from_be_bytes(arr_byte))
    }
    pub fn read_u16_le(&mut self) -> io::Result<u16> {
        let arr_byte = self.read_2()?;
        Ok(u16::from_le_bytes(arr_byte))
    }
    pub fn read_u16_be(&mut self) -> io::Result<u16> {
        let arr_byte = self.read_2()?;
        Ok(u16::from_be_bytes(arr_byte))
    }
}


impl BytesIO {

    pub fn read_i24_le(&mut self) -> io::Result<i32> {
        let arr_byte = self.read_bytes(3)?;
        let val = (arr_byte[0] as i32) + ((arr_byte[1] as i32) << 8) + (((arr_byte[2] & 127) as i32) << 16);
        if arr_byte[2] & 0x80 > 0 {
            Ok(-val)
        } else {
            Ok(val)
        }
    }
    pub fn read_i24_be(&mut self) -> io::Result<i32> {
        let arr_byte = self.read_bytes(3)?;
        let val = (arr_byte[2] as i32) + ((arr_byte[1] as i32) << 8) + (((arr_byte[0] & 127) as i32) << 16);
        if arr_byte[0]& 0x80 > 0 {
            Ok(-val)
        } else {
            Ok(val)
        }
    }

    pub fn read_u24_le(&mut self) -> io::Result<u32> {
        let arr_byte = self.read_bytes(3)?;
        let val = (arr_byte[0] as u32) + ((arr_byte[1] as u32) << 8) + ((arr_byte[2] as u32) << 16);
        Ok(val)
    }
    pub fn read_u24_be(&mut self) -> io::Result<u32> {
        let arr_byte = self.read_bytes(3)?;
        let val = (arr_byte[2] as u32) + ((arr_byte[1] as u32) << 8) + ((arr_byte[0] as u32) << 16);
        Ok(val)
    }
}


impl BytesIO {
    
    pub fn read_f32_ibm(&mut self) -> io::Result<f32> {
        let arr_byte = self.read_4()?;
        let sign = if (arr_byte[0] & 0x80) > 0 { -1.0 } else { 1.0 };
        let a = (arr_byte[0] & 0x7f) as i32;
        let b = (((arr_byte[1] as i32) << 16) + ((arr_byte[2] as i32) << 8) + arr_byte[3] as i32) as f32;

        let val = sign * 2.0f32.powi(-24) * b * 16.0f32.powi(a - 64);
        Ok(val)
    }

}


impl BytesIO {
    pub fn read_i32_le(&mut self) -> io::Result<i32> {
        let arr_byte = self.read_4()?;
        Ok(i32::from_le_bytes(arr_byte))
    }
    pub fn read_i32_be(&mut self) -> io::Result<i32> {
        let arr_byte = self.read_4()?;
        Ok(i32::from_be_bytes(arr_byte))
    }
    pub fn read_u32_le(&mut self) -> io::Result<u32> {
        let arr_byte = self.read_4()?;
        Ok(u32::from_le_bytes(arr_byte))
    }
    pub fn read_u32_be(&mut self) -> io::Result<u32> {
        let arr_byte = self.read_4()?;
        Ok(u32::from_be_bytes(arr_byte))
    }

    
    pub fn read_f32_le(&mut self) -> io::Result<f32> {
        let arr_byte = self.read_4()?;
        let val = u32::from_le_bytes(arr_byte);
        Ok(f32::from_bits(val))
    }
    pub fn read_f32_be(&mut self) -> io::Result<f32> {
        let arr_byte = self.read_4()?;
        let val = u32::from_be_bytes(arr_byte);
        Ok(f32::from_bits(val))
    }
}


impl BytesIO {
    pub fn read_i64_le(&mut self) -> io::Result<i64> {
        let arr_byte = self.read_8()?;
        Ok(i64::from_le_bytes(arr_byte))
    }
    pub fn read_i64_be(&mut self) -> io::Result<i64> {
        let arr_byte = self.read_8()?;
        Ok(i64::from_be_bytes(arr_byte))
    }
    pub fn read_u64_le(&mut self) -> io::Result<u64> {
        let arr_byte = self.read_8()?;
        Ok(u64::from_le_bytes(arr_byte))
    }
    pub fn read_u64_be(&mut self) -> io::Result<u64> {
        let arr_byte = self.read_8()?;
        Ok(u64::from_be_bytes(arr_byte))
    }

    pub fn read_f64_le(&mut self) -> io::Result<f64> {
        let arr_byte = self.read_8()?;
        let val = u64::from_le_bytes(arr_byte);
        Ok(f64::from_bits(val))
    }
    pub fn read_f64_be(&mut self) -> io::Result<f64> {
        let arr_byte = self.read_8()?;
        let val = u64::from_be_bytes(arr_byte);
        Ok(f64::from_bits(val))
    }
}


impl BytesIO {
    pub fn read_i128_le(&mut self) -> io::Result<i128> {
        let arr_byte = self.read_16()?;
        Ok(i128::from_le_bytes(arr_byte))
    }
    pub fn read_i128_be(&mut self) -> io::Result<i128> {
        let arr_byte = self.read_16()?;
        Ok(i128::from_be_bytes(arr_byte))
    }
    pub fn read_u128_le(&mut self) -> io::Result<u128> {
        let arr_byte = self.read_16()?;
        Ok(u128::from_le_bytes(arr_byte))
    }
    pub fn read_u128_be(&mut self) -> io::Result<u128> {
        let arr_byte = self.read_16()?;
        Ok(u128::from_be_bytes(arr_byte))
    }
}


impl BytesIO {
    pub fn iter_utf8_lines(bts: Vec<u8>) -> io::Lines<BufReader<BytesIO>> {
        let bytes_io = BytesIO::from_bytes("utf-8".to_string(), bts);
        let reader = BufReader::new(bytes_io);
        reader.lines()
    }

    pub fn read_utf8_lines(bts: Vec<u8>) -> IResult<Vec<String>> {
        /*
        \n : 换行符（newline），另起一行，对应ASCII 值10（缩写：LF）。 \r : 回车符（return），回到一行的开头，对应ASCII 值13（缩写：CR）。
         */
        const ASCII_N: u8 = 10;
        const ASCII_R: u8 = 13;

        let mut lines = vec![];
        let mut line: Vec<u8> = Vec::with_capacity(4096);
        for bt in bts {
            if bt == ASCII_N || bt == ASCII_R {
                let line_new = std::str::from_utf8(&line)?;
                lines.push(line_new.to_string());
                line.clear();
            } else {
                line.push(bt);
            }
        }
        if line.len() > 0 {
            let line_new = std::str::from_utf8(&line)?;
            lines.push(line_new.to_string());
        }
        
        Ok(lines)
    }


    pub fn read_gbk_lines(bts: Vec<u8>) -> IResult<Vec<String>> {
        /*
        \n : 换行符（newline），另起一行，对应ASCII 值10（缩写：LF）。 \r : 回车符（return），回到一行的开头，对应ASCII 值13（缩写：CR）。
         */
        const ASCII_N: u8 = 10;
        const ASCII_R: u8 = 13;
        let encoding = encoding_rs::GBK;

        let mut lines = vec![];
        let mut line: Vec<u8> = Vec::with_capacity(4096);
        for bt in bts {
            if bt == ASCII_N || bt == ASCII_R {
                let line_new = line.clone();
                let (cow, encoding_used, had_errors) = encoding.decode(&line_new);
                if had_errors {
                    let msg = format!("BytesIO::read_lines: with {}({} used) encoding error: {}", encoding.name(), encoding_used.name(), cow.as_ref());
                    return Err(msg.as_str())?;
                }
                lines.push(cow.as_ref().to_string());
                line.clear();
            } else {
                line.push(bt);
            }
        }
        if line.len() > 0 {
            let line_new = line.clone();
            let (cow, encoding_used, had_errors) = encoding.decode(&line_new);
            if had_errors {
                let msg = format!("BytesIO::read_lines: with {}({} used) encoding error: {}", encoding.name(), encoding_used.name(), cow.as_ref());
                return Err(msg.as_str())?;
            }
            lines.push(cow.as_ref().to_string());
        }
        
        Ok(lines)
    }

    pub fn read_lines(bts: Vec<u8>, encoding: &'static Encoding) -> IResult<Vec<String>> {
        /*
        \n : 换行符（newline），另起一行，对应ASCII 值10（缩写：LF）。 \r : 回车符（return），回到一行的开头，对应ASCII 值13（缩写：CR）。
         */
        const ASCII_N: u8 = 10;
        const ASCII_R: u8 = 13;

        let mut lines = vec![];
        let mut line: Vec<u8> = Vec::with_capacity(4096);
        for bt in bts {
            if bt == ASCII_N || bt == ASCII_R {
                let line_new = line.clone();
                let (cow, encoding_used, had_errors) = encoding.decode(&line_new);
                if had_errors {
                    let msg = format!("BytesIO::read_lines: with {}({} used) encoding error: {}", encoding.name(), encoding_used.name(), cow.as_ref());
                    return Err(msg.as_str())?;
                }
                lines.push(cow.as_ref().to_string());
                line.clear();
            } else {
                line.push(bt);
            }
        }
        if line.len() > 0 {
            let line_new = line.clone();
            let (cow, encoding_used, had_errors) = encoding.decode(&line_new);
            if had_errors {
                let msg = format!("BytesIO::read_lines: with {}({} used) encoding error: {}", encoding.name(), encoding_used.name(), cow.as_ref());
                return Err(msg.as_str())?;
            }
            lines.push(cow.as_ref().to_string());
        }
        
        Ok(lines)
    }


    pub fn split_bytes(bts: Vec<u8>) -> Vec<Vec<u8>> {
        /*
        \n : 换行符（newline），另起一行，对应ASCII 值10（缩写：LF）。 \r : 回车符（return），回到一行的开头，对应ASCII 值13（缩写：CR）。
         */
        const ASCII_N: u8 = 10;
        const ASCII_R: u8 = 13;

        let mut lines: Vec<Vec<u8>> = vec![];
        let mut line: Vec<u8> = Vec::with_capacity(4096);
        for bt in bts {
            if bt == ASCII_N || bt == ASCII_R {
                lines.push(line.clone());
                line.clear();
            } else {
                line.push(bt);
            }
        }
        if line.len() > 0 {
            lines.push(line.clone());
        }
        lines
    }
}


impl BytesIO {

    pub fn lines_counter(bts: &Vec<u8>) -> (u32, u32) {
        /*
        \n : 换行符（newline），另起一行，对应ASCII 值10（缩写：LF）。 \r : 回车符（return），回到一行的开头，对应ASCII 值13（缩写：CR）。
         */
        const ASCII_N: u8 = 10;
        const ASCII_R: u8 = 13;

        let mut n_count = 0;
        let mut r_count = 0;
        
        for &bt in bts {
            if bt == ASCII_N {
                n_count += 1;
            } else if bt == ASCII_R {
                r_count += 1;
            }
        }
        
        (n_count, r_count)
    }
    
}

